package org.atlantis.net.nio;

import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerHandler {

	private int bufSize;

	public ServerHandler(int bufSize) {
		this.bufSize = bufSize;
	}

	public void handleAccept(SelectionKey key) throws Exception {
		SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
		socketChannel.configureBlocking(false); // 设置客户端的Channel为非阻塞
		/*
		 * 关注客户端（SocketChannel）的读写。
		 * 只要客戶端的一连接，那就永远是可写的（即：每次都会触发OP_WRITE事件），而当客户端向服务器
		 * 发送消息时，那就是可读的（即：会触发OP_READ事件）。
		 */
		socketChannel.register(key.selector(), SelectionKey.OP_READ | SelectionKey.OP_WRITE,
				ByteBuffer.allocate(bufSize));
		System.out.println(String.format("A client<%s> connected.", socketChannel.socket().getInetAddress()));
	}

	/*
	 * 客户端如果正常断开连接，也会发送一个特殊的消息（这个消息是说明客户端断开了），所以也会触发可读事件。
	 * 并且这个时候读取到的值是-1，这样就可以知道客户端断开了连接。所以如果客户端不断开，那么read方法就 永远不可能返回-1。
	 */
	public void handleRead(SelectionKey key) throws Exception {
		SocketChannel socketChannel = (SocketChannel) key.channel();
		ByteBuffer buf = (ByteBuffer) key.attachment();
		long bytesRead = socketChannel.read(buf);
		if (bytesRead == -1) {
			System.err.println(String.format("A client<%s> disconnected.", socketChannel.socket().getInetAddress()));
			// 关闭服务器到客户端的连接，否则会一直触发可读事件，并且read一直返回-1
			socketChannel.close();
		}
	}

	public void handleWrite(SelectionKey key) throws Exception {
		ByteBuffer buf = (ByteBuffer) key.attachment();
		buf.flip();
		SocketChannel socketChannel = (SocketChannel) key.channel();
		socketChannel.write(buf);
		buf.compact();
	}
}
